package com.china.zhuoyue.api.core

import androidx.lifecycle.Observer
import com.china.zhuoyue.api.core.enums.ApiCode
import kotlinx.coroutines.*
import java.io.Closeable
import java.io.IOException
import kotlin.coroutines.CoroutineContext

typealias ApiError = ((Throwable) -> Unit)
typealias ApiComplete = () -> Unit

//fun <T> ResultBean<T>.toData(): T? =
//    if (isOk) (data) else throw FirmException(errmsg, errno, data)
/**
 * 统一数据封装类
 */
//data class WrapResultBean<Any>(
//    var errno: Int = -1,
//    var errmsg: String? = null,
//    var data: T? = null
//) : IResult<T> {
//    companion object {
//        const val SUCCESS = 0
//        const val NOT_LOGIN = 401 //未登录或登录失效
//        const val SERVICE_ERROR = 500 //服务器内部错误
//    }
//
//    override fun isOk() = errno == SUCCESS
//
//    override fun getTData() = data
//
//    override fun getErrorMsg() = errmsg
//}

/**
 * 业务异常类
 */
class FirmException(override var message: String? = "", val code: Int, val data: Any?) :
    RuntimeException(message)

/**
 * 在OKHTTP拦截器里面只能抛该异常否则协程会无法捕获异常导致程序崩溃
 */
class InterceptorException(override var message: String? = "") : IOException(message)

/**
 * 自定义网络常类
 */
class NotNetworkException : RuntimeException("")

//fun <T> ComponentActivity.launchUI(
//    block: suspend ApiService.() -> T,
//    apiObserver: Observer<ApiProcess<T>>? = null,
//    error: ApiError? = null,
//    complete: ApiComplete? = null
//): Job = ApiRequest(lifecycleScope).launchUI(block, error, complete, apiObserver)
//
//fun <T> Fragment.launchUI(
//    block: suspend ApiService.() -> T,
//    apiObserver: Observer<ApiProcess<T>>? = null,
//    error: ApiError? = null,
//    complete: ApiComplete? = null,
//): Job = ApiRequest(lifecycleScope).launchUI(block, error, complete, apiObserver)
//
//fun <T> ViewModel.launchUI(
//    block: suspend ApiService.() -> T,
//    apiObserver: Observer<ApiProcess<T>>? = null,
//    error: ApiError? = null,
//    complete: ApiComplete? = null
//): Job = ApiRequest(viewModelScope).launchUI(block, error, complete, apiObserver)

//fun <T> globalLaunchUI(
//    block: suspend ApiService.() -> T,
//    apiObserver: Observer<ApiProcess<T>>? = null,
//    error: ApiError? = null,
//    complete: ApiComplete? = null
//): Job = ApiRequest(uiScope()).launchUI(block, error, complete, apiObserver)

/**
 * 使用类的方式调用方便以后实现重试机制
 * 调用方式
 * launchUI({网络请求},ApiObserver())
val test: ApiLiveData<String> = ApiLiveData()
 * launchUI({网络请求},test)
 */
class ApiRequest<ApiService>(
    private val scope: CoroutineScope,
    private val apiService: ApiService
) {
    companion object {
        private const val RETRY_DELAY_MILLIS = 2000
        private const val MAX_RETRIES = 3
    }

    private val maxRetries: Int = MAX_RETRIES
    private val retryDelayMillis: Int = RETRY_DELAY_MILLIS
    fun <T> launchUI(
        block: suspend ApiService.() -> T,
        error: ApiError? = null,
        complete: ApiComplete? = null,
    ): Job = launchUI(block, error, complete, null)

    fun <T> launchUI(
        block: suspend ApiService.() -> T,
        error: ApiError? = null,
        complete: ApiComplete? = null,
        apiObserver: Observer<ApiProcess<T>>? = null
    ): Job {
        apiObserver?.onChanged(ApiProcess())
        return scope.launch(CoroutineExceptionHandler { _, throwable ->
            error?.invoke(throwable)
            apiObserver?.onChanged(ApiProcess(apiCode = ApiCode.ERROR, throwable = throwable))
            apiObserver?.onChanged(ApiProcess(apiCode = ApiCode.COMPLETE))
        }) {
            try {
                val result = apiService.block()
                apiObserver?.onChanged(ApiProcess(apiCode = ApiCode.SUCCESS, data = result))
            } catch (e: Throwable) {
                // 后续扩展实现重试机制
                try {
                    error?.invoke(e)
                    apiObserver?.onChanged(ApiProcess(apiCode = ApiCode.ERROR, throwable = e))
                } catch (e1: Exception) {
                    apiObserver?.onChanged(ApiProcess(apiCode = ApiCode.ERROR, throwable = e1))
                }
            }
            try {
                complete?.invoke()
                apiObserver?.onChanged(ApiProcess(ApiCode.COMPLETE))
            } catch (e1: Exception) {
                apiObserver?.onChanged(ApiProcess(ApiCode.COMPLETE))
            }
        }
    }
}

/**
 * 返回livedata方式请求接口；目前接口统一定义在ApiService；这种方式订阅者必须传递生命周期组件否则可能会内存泄漏
 * @param error 请求错误回调
 * @param complete 请求完成回调
 * @param block 请求代码块，最后一行的返回结果会传递到订阅者
 * 请求示例
 * apiLiveData { queryOrg("").toData() }.observe(this, ApiObserver(loadService = mLoadService) {
 *  TODO 自己的业务逻辑
 * })
 */
//fun <T, ApiService> apiLiveData(
//    error: ApiError? = null,
//    complete: ApiComplete? = null,
//    block: suspend ApiService.() -> T,
//) = liveData<ApiProcess<T>>(CoroutineExceptionHandler { _, throwable ->
//    error?.invoke(throwable)
//}) {
//    kotlin.runCatching { emit(ApiProcess()) }
//    try {
//        val result: T = SERVICE.block()
//        kotlin.runCatching { emit(ApiProcess(apiCode = ApiCode.SUCCESS, data = result)) }
//    } catch (throwable: Throwable) {
//        kotlin.runCatching { emit(ApiProcess(apiCode = ApiCode.ERROR, throwable = throwable)) }
//    }
//    kotlin.runCatching { complete?.invoke() }
//    kotlin.runCatching { emit(ApiProcess(ApiCode.COMPLETE)) }
//}

/**
 * 在非viewmodel地方使用
 */
fun uiScope() = SafeCoroutineScope(Dispatchers.Main)

class SafeCoroutineScope(context: CoroutineContext) : CoroutineScope, Closeable {
    override val coroutineContext: CoroutineContext = SupervisorJob() + context

    override fun close() {
        coroutineContext.cancelChildren()
    }
}